import datetime

from celery.result import AsyncResult
from django.core.mail import send_mail
from django.db.models import Count, Q
from django.http import Http404
from rest_framework import status
from rest_framework.exceptions import ValidationError
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser
from rest_framework.views import APIView
from rest_framework_simplejwt.views import TokenViewBase

from Lab301 import settings
from Submission.config import Verdict
from Utils.BaseResponse import BaseResponse
from Utils.GetUserFromToken import get_username_from_request
from .authenticate import MyJSONWebTokenAuthentication
from .models import Person, RejesterCode, PersonDetail
from .serializers import PersonSerializer, PersonRegisterSerializer, MyTokenObtainPairSerializer, GetPersonDetail, \
    CommonUserRegisterSerializer, PersonAdminListSerializer, PersonRankSerializer


# 创建视图在此处

# 自定义 jwt 返回的类型
class LoginView(TokenViewBase):
    serializer_class = MyTokenObtainPairSerializer

    def post(self, request, *args, **kwargs):
        try:
            serializer = self.get_serializer(data=request.data)
            if serializer.is_valid():
                return BaseResponse(serializer.validated_data, status=status.HTTP_200_OK).success()
        except:
            return BaseResponse(status=status.HTTP_400_BAD_REQUEST).fail("账号或密码错误")


# 用户信息管理API视图，用于获取所有用户信息或添加单个用户信息
class PersonAPIView(APIView):
    """
    获取所有用户信息或添加单个用户信息
    """
    authentication_classes = []  # 登录认证
    permission_classes = [AllowAny, ]  # 配置了权限类，没登录的就没有权限访问了

    # GET 方法：获取所有用户信息
    def get(self, request, format=None):
        """
        获取所有Person对象的信息
        :param request: 请求对象，包含请求信息
        :param format: 请求的数据格式，默认为None，允许客户端指定返回数据的格式
        :return: 返回包含所有用户信息的序列化数据以及200 OK状态码
        """
        # 获取所有用户实例
        persons = Person.objects.all()
        # 序列化所有用户信息
        serializer = PersonSerializer(persons, many=True)
        # 返回序列化后的用户数据
        return BaseResponse(serializer.data, status=status.HTTP_200_OK).success()

    # POST 方法：注册一个用户
    def post(self, request, format=None):
        """
        添加单个用户信息
        :param request: 请求对象，包含需要添加的用户信息
        :request.data 格式示例：
        {
            "username": "weiqtsddff",
            "email": "2365164682@qq.com",
            "password": "weiqt"
        }
        :param format: 请求的数据格式，默认为None，允许客户端指定发送数据的格式
        :return: 如果数据有效且保存成功，返回新建用户的序列化数据以及201 CREATED状态码；否则返回400 BAD REQUEST状态码和错误信息
        """
        # 创建并初始化用户注册序列化器
        serializer = PersonRegisterSerializer(data=request.data)
        # 验证并保存用户信息
        if serializer.is_valid():
            try:
                # 保存成功，返回新建用户的数据及成功消息
                serializer.save()
                return BaseResponse(serializer.data, status=status.HTTP_201_CREATED).success()
            except Exception as e:
                return BaseResponse(str(e), status=status.HTTP_400_BAD_REQUEST).fail("注册失败")
        # 验证失败，返回错误信息及400 BAD REQUEST状态码
        return BaseResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST).fail("不合法的数据")


# 用户详细信息管理API视图，用于检索或删除单个用户信息
class PersonDetailAPIView(APIView):
    """
    检索或删除单个用户信息
    """

    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated]  # 配置了权限类，没登录的就没有权限访问了

    # 定义获取单个用户的方法
    def get_object(self, pk):
        """
        根据主键查找Person对象
        :param pk: 要查找的Person对象的主键
        :return: 查找到的Person对象，若未找到则抛出Http404异常
        """
        try:
            return Person.objects.get(pk=pk)
        except Person.DoesNotExist:
            raise Http404

    # GET 方法：获取单个用户信息
    def get(self, request, pk, format=None):
        """
        获取单个Person对象的信息
        :param request: 请求对象，包含请求信息
        :param pk: 需要获取的Person对象的主键
        :param format: 请求的数据格式，默认为None，允许客户端指定返回数据的格式
        :return: 如果找到对应用户，则返回其序列化后的信息以及200 OK状态码；否则返回404 NOT FOUND状态码及错误信息
        """
        try:
            # 根据主键获取用户对象
            person = self.get_object(pk)
        except Http404:
            # 用户对象不存在，返回错误信息及状态码
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(f"对象不存在,不合法的 pk:{pk}")

        # 序列化并返回用户信息
        serializer = PersonSerializer(person)
        return BaseResponse(serializer.data, status=status.HTTP_200_OK).success()

    # PUT 方法：更新单个用户信息
    def put(self, request, pk, format=None):
        """
        更新单个Person对象的信息
        :param request: 请求对象，包含待更新的用户信息
        :param pk: 需要更新的Person对象的主键
        :param format: 请求的数据格式，默认为None，允许客户端指定发送数据的格式
        :return: 如果数据有效且更新成功，返回更新后的用户信息以及200 OK状态码；否则返回400 BAD REQUEST状态码和错误信息
        """
        try:
            # 根据主键获取用户对象
            person = self.get_object(pk)
        except Http404:
            # 用户对象不存在，返回错误信息及状态码
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(f"对象不存在,不合法的 pk:{pk}")

        # 更新并验证用户信息
        serializer = PersonSerializer(person, data=request.data)
        if serializer.is_valid():
            serializer.save()
            # 更新成功，返回更新后的用户数据及成功消息
            return BaseResponse(serializer.data, status=status.HTTP_200_OK).success()
        # 更新失败，返回错误信息及400 BAD REQUEST状态码
        return BaseResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST).fail("不合法的数据")

    # DELETE 方法：删除单个用户信息
    def delete(self, request, pk, format=None):
        """
        删除单个Person对象
        :param request: 请求对象，包含删除请求信息
        :param pk: 需要删除的Person对象的主键
        :param format: 请求的数据格式，默认为None，此方法不受此参数影响
        :return: 如果删除成功，则返回204 NO CONTENT状态码；否则返回404 NOT FOUND状态码及错误信息
        """
        try:
            # 根据主键获取用户对象
            person = self.get_object(pk)
        except Http404:
            # 用户对象不存在，返回错误信息及状态码
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(f"对象不存在,不合法的 pk:{pk}")

        # 删除用户对象
        person.delete()
        # 返回删除成功的消息及204 NO CONTENT状态码
        return BaseResponse(status=status.HTTP_204_NO_CONTENT).success()


class GetPersonDetailAPIView(APIView):
    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated]  # 配置了权限类，没登录的就没有权限访问了

    def get(self, request, format=None):
        username = get_username_from_request(request.headers.get('Authorization'))
        if request.query_params.get('username'):
            username = request.query_params.get('username')
        if username is None:
            return BaseResponse(status=status.HTTP_400_BAD_REQUEST).fail("未传入username")
        try:
            # 根据用户名获取用户对象
            person = Person.objects.get(username=username)
        except Http404:
            # 用户对象不存在，返回错误信息及状态码
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(f"不存在的用户名:{username}")

        # 序列化并返回用户信息
        serializer = GetPersonDetail(instance=person)
        return BaseResponse(serializer.data, status=status.HTTP_200_OK).success()

    def post(self, request, format=None):
        # 提取请求数据
        username = request.data.get('username')
        luck = request.data.get('luck')
        today = datetime.datetime.now().date()
        # 查找对应的用户
        try:
            person = Person.objects.get(username=username)
        except Person.DoesNotExist:
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail("用户不存在")
        # 获取用户的个人详细信息
        person_detail, created = PersonDetail.objects.get_or_create(person=person)
        # 检查上次签到时间是否为今天
        if person_detail.last_clockin and person_detail.last_clockin == today:
            # 如果是今天已经签到过了，返回已签到信息和数据库中的幸运值
            return BaseResponse({"luck": person_detail.luck}, status=status.HTTP_400_BAD_REQUEST).fail(
                "今天已经签到过了")
        else:
            # 如果今天还没有签到，则更新数据库中的幸运值和上次签到时间
            person_detail.luck = luck
            person_detail.last_clockin = today
            person_detail.save()
            return BaseResponse(status=status.HTTP_200_OK).success("签到成功")


class SendCodeAPIView(APIView):
    def post(self, request, format=None):
        email = request.data.get('email')
        if email is None:
            return BaseResponse(status=status.HTTP_400_BAD_REQUEST).fail("邮箱不能为空")

        # 判断该邮箱是否已被注册
        if Person.objects.filter(email=email).exists():
            return BaseResponse(status=status.HTTP_400_BAD_REQUEST).fail("该邮箱已被注册")

        import string
        import random
        code_characters = string.ascii_letters + string.digits  # 包含大小写字母和数字
        code_length = 10
        verification_code = ''.join(random.choice(code_characters) for _ in range(code_length))
        from_who = settings.EMAIL_FROM  # 发件人 已经写在配置中
        to_who = email  # 收件人
        subject = 'Lab301发送验证码'  # 发送的主题
        # 发送的消息
        message = '注册信息'  # 发送普通的消息使用的时候message
        meg_html = f"""
                <div style="height: 400px;background-color: whitesmoke;margin: 0 auto;">
             <h2 style="text-align: center;padding-top: 15px;">Lab301邮件验证系统</h2>
             <div style="margin: 0 auto;background-color: white;height: 200px;width: 500px;border: 1px solid rgb(172, 172, 172);">
                  <h3 style="border-bottom: 1px solid  rgb(172, 172, 172);height: 40px;line-height: 40px;margin-top: 0;padding-left: 25px;">注册验证</h3>
                  <p style="margin-left: 25px;color:steelblue;">你好!{email}</p>
                  <p style="margin-left: 25px;color:steelblue;">欢迎注册Lab301管理系统网站，请将注册码在十分钟内填到相应页面</p>
                  <p style="margin-left: 25px;color:steelblue;">您的验证码是：{verification_code}</p>
              </div>
        </div>
        """

        rejester_code = RejesterCode.objects.filter(email=email).first()
        if rejester_code is not None:
            rejester_code.verification_code = verification_code
            rejester_code.is_active = True
            rejester_code.expires = datetime.datetime.now() + datetime.timedelta(seconds=settings.EMAIL_TIMEOUT)
            rejester_code.save()
        else:
            # 发送一个html
            RejesterCode.objects.create(email=email, verification_code=verification_code, is_active=True,
                                        expires=datetime.datetime.now() + datetime.timedelta(
                                            seconds=settings.EMAIL_TIMEOUT))

        send_mail(subject, message, from_who, [to_who], html_message=meg_html,fail_silently=False)

        return BaseResponse(data={'message': "发送成功"}, status=status.HTTP_200_OK).success()


class RegisterAPIView(APIView):
    def post(self, request, format=None):
        serializer = CommonUserRegisterSerializer(data=request.data)
        if serializer.is_valid():
            try:
                serializer.save()
                return BaseResponse(data=serializer.data, status=status.HTTP_201_CREATED).success()
            except ValidationError as e:
                return BaseResponse(data=str(e), status=status.HTTP_400_BAD_REQUEST).fail("注册失败" + str(e))
            except Exception as e:
                return BaseResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST).fail("不合法的数据")


class PersonAdmin(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Person.objects.all()
    serializer_class = PersonAdminListSerializer

    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated, IsAdminUser]

    def get(self, request, format=None):
        res = self.list(request)
        if res.status_code == 200:
            return BaseResponse(data={"list": res.data}, status=status.HTTP_200_OK).success()
        return BaseResponse(data=res.data, status=status.HTTP_400_BAD_REQUEST).fail()

    def post(self, request, format=None):
        res = self.create(request)
        if res.status_code == status.HTTP_201_CREATED:
            return BaseResponse(data=res.data, status=status.HTTP_201_CREATED).success()
        return BaseResponse(data=res.data, status=status.HTTP_400_BAD_REQUEST).fail()


class PersonRank(APIView):
    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated]  # 配置了权限类，没登录的就没有权限访问了

    def get(self, request):
        person_with_submits = Person.objects.annotate(
            total_submit=Count('user_submissions'),  # 假设外键名为 'submission'
            success_submit=Count('user_submissions', filter=Q(user_submissions__verdict=Verdict.ACCEPTED))
            # 假设状态字段名为 'status'，'accepted' 表示通过
        ).order_by('-total_submit')

        serializer = PersonRankSerializer(person_with_submits, many=True)
        ranked_data = []
        for index, serialized_person in enumerate(serializer.data):
            serialized_person['rank'] = index + 1
            ranked_data.append(serialized_person)

        return BaseResponse(data={"list": ranked_data}, status=status.HTTP_200_OK).success()


class CeleryAdminTask(APIView):
    authentication_classes = [MyJSONWebTokenAuthentication]
    permission_classes = [IsAuthenticated, IsAdminUser]

    def post(self, request, format=None):
        task = AsyncResult(request.data.get('task_id'))
        if task.state == 'SUCCESS':
            response_data = {"status": "completed", "result": task.result}
        elif task.state in ['PENDING', 'STARTED', 'RETRY']:
            response_data = {"status": "running", "state": task.state}
        else:
            response_data = {"status": "failed"}

        return BaseResponse(data={'result': task.state, 'info': response_data}, status=status.HTTP_200_OK).success()
